package com.leyou.sms.utils;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.leyou.sms.config.SmsProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @Author: Rose
 * @Date: 2021/4/9 13:25
 * @description ${description}
 * @version: 1.0.0
 */

@Slf4j
@Component
@EnableConfigurationProperties(SmsProperties.class)
public class SmsUtils {

    @Autowired
    private SmsProperties smsProperties;

    // 产品名称： 云通信短信API 产品， 开发者无需替换
    private static final String product = "Dysmsapi";

    // 产品域名，开发这无需替换
    public static final String domain = "dysmsapi.aliyuncs.com";

    public static final String SMS_KEY_PREFIX = "sms:phone";

    public static final long SMS_MIN_INTERVAL_IN_MILLIS = 60000;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    public SendSmsResponse sendSms(String phoneNumber, String signName, String templateCode, String templateParam) {

        String key = SMS_KEY_PREFIX + ":" + templateCode + ":" + phoneNumber;

        // TODO 在此处可以按照 手机号码 做限流， 限制短信的发送频率
        // 在此处取出 时间 ，去对比， 看上次发送的时间是否超过 一定的时间
        // 短信发送成功， 在Redis 中记录本次发送短信的 时间
        // 判断key 是否存在
        Boolean keyExists = stringRedisTemplate.hasKey(key);
        /*if(keyExists) {
            BoundHashOperations<String, Object, Object> boundHashOps = stringRedisTemplate.boundHashOps(key);
            Boolean times = boundHashOps.hasKey("times");
            if (times) {
                long longTime = Long.parseLong(boundHashOps.get("times").toString());
                if (longTime >= 5 ) {
                    log.info("[短信服务] 发送短信失败, 手机号码:{} ,失败原因：发送频率过高, 被拦截！" ,phoneNumber);
                    return  null;
                }else {
                    Long time = (Long) boundHashOps.get(longTime);

                    if(System.currentTimeMillis() - time < SMS_MIN_INTERVAL_IN_MILLIS){
                        log.info("[短信服务] 发送短信失败, 手机号码:{} ,失败原因：发送频率过高！, 被拦截！" ,phoneNumber);
                        return null;
                    }
                }
            }
        }*/

        try {
            // 可自主调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");

            // 初始化 accClient,暂不支持 region 化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", smsProperties.getAccessKeyId(), smsProperties.getAccessKeySecret());
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
            IAcsClient acsClient = new DefaultAcsClient(profile);


            // 组装请求对象 -- 具体描述见控制台 -文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            request.setSysMethod(MethodType.POST);
            // 必填: 待发送手机号
            request.setPhoneNumbers(phoneNumber);
            // 必填： 短信签名- 可在短信控制台中找到
            request.setSignName(StringUtils.isBlank(signName) ? smsProperties.getSignName() : signName);
            // 必填： 短信模板 -可在短信控制台中找到
            request.setTemplateCode(StringUtils.isBlank(templateCode) ? smsProperties.getVerifyCodeTemplate() : templateCode);
            // 可选： 模板中的变量替换JSON串， 如模板内容为： “亲爱的${name}，你的验证码为${code}”时， 此处的值为
            request.setTemplateParam(templateParam);

            // 选填 上行短信扩展码（无特殊绣球用户请忽略次字段）
            // request.setSmsUpExtendCode("");

            // 可选： outId 为提供给业务房扩展字段，最终在短信执行消息中将辞职带回给调用者
            request.setOutId("");

            // hint 此处可能会抛出异常， 注意： catch
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);

            if (!"OK".equals(sendSmsResponse.getCode())) {
                log.info("[短信服务] 发送短信失败， phoneNumber:{}, 原因:{}", phoneNumber, sendSmsResponse.getMessage());
            }


            BoundHashOperations<String, Object, Object> boundHashOps = stringRedisTemplate.boundHashOps(key);
            // 发送次数
            Object o = boundHashOps.get("times");
            long longTime;
            if (o == null) {
                longTime = 0;
            } else {
                longTime = Long.parseLong(o.toString());
            }
            boundHashOps.put("times", longTime + 1);
            // 本次发送成功的时间 ，记录
            boundHashOps.put(longTime, String.valueOf(System.currentTimeMillis()));

            // 设置key 的过期时间
            stringRedisTemplate.expire(key, 3600, TimeUnit.SECONDS);

            log.info("[短信服务] 发送短信验证码, 手机号码:{}", phoneNumber);

            return sendSmsResponse;

        } catch (Exception e) {
            log.error("[短信服务] 发送短信异常, 手机号码:{},异常信息为:{}", phoneNumber, e.getMessage());
        }
        return null;
    }
}
